﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using WindowsFormsApplication1;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ComboBox_Init();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen == false)                        //读取端口状态，是否已打开
            {
                serialPort1.PortName = CMB_Port.Text;               //设置端口号
                serialPort1.BaudRate = 115200;
                try                                                 //容错处理开始
                {
                    serialPort1.Open();                             //打开端口
                    BTN_OPEN.Text = "Close";                        //按键名字改为Close
                    TB_Receive.Text = "\r\n等待设备连接···";
                    

                }
                catch (Exception err)                               //处理错误
                {
                    MessageBox.Show(err.Message);                   //弹出错误对话框
                    BTN_OPEN.Text = "Open";
                }
            }
            else if (serialPort1.IsOpen == true)                    //若端口已打开，则关闭端口
            {
                serialPort1.Close();
                BTN_OPEN.Text = "Open";
            }
        }


        private void ComboBox_Init()
        {
            string[]  sAllPort = SerialPort.GetPortNames();                                 //读取可用串口
            CMB_Port.Items.Clear();
            CMB_Port.Items.AddRange(sAllPort);          //设置COM口
        }

        DataPack_typdef UartPack = new DataPack_typdef();

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            UInt16 i;

            UartPack.Data = new byte[1024];

            int number = serialPort1.BytesToRead;       //读取缓冲区内字节数目

            byte[] buff = new byte[number];             //申请一个BUFF

            serialPort1.Read(buff, 0, number);          //读取数据
            Console.WriteLine("number = {0 :D}", number);
            for (i = 0; i < number; i++)
            {

                UartPack.PacketParsing(buff[i]);
                if (UartPack.Status == ReceiveStatus.RX_CarryOut)
                {
                    UartPack.Status = ReceiveStatus.RX_Free;
                    
                    ResponseCmd(UartPack.CMD);
                }
                
            }
        }

        
        public void TB_ReceiveAddStr(string str)
        {
            this.Invoke((EventHandler)(delegate         //中断为另外一个线程，所以需 夸线程操作UI需要这么做 //访问 UI所需，暂不明白为什么要这么做
            {
                this.TB_Receive.AppendText(str);

            }));
        }
        /*********************************************************************************
        * 单击打开文件按钮触发事件
        * 获取用户选择文件路径，输出文件路径到显示窗口
        *********************************************************************************/
        OpenFileDialog ofd = new OpenFileDialog();
        private void BTN_OpenFile_Click(object sender, EventArgs e)
        {
            string str = "";

            ofd.Title = "打开";
            ofd.Filter = "bin|*.bin*";
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                str = ofd.FileName;
                TB_Receive.AppendText("\r\n" + str);
            }
        }
        /*********************************************************************************
        * UpDate按钮处罚事件
        * 重载用户选择文件，发送到下位机
        *********************************************************************************/
        private void BTN_UpDate_Click(object sender, EventArgs e)
        {

            if (ofd.FileName == "")
            {
                //TB_Receive.Text += "\r\n请选择目标文件``````````````";
                TB_Receive.AppendText("\r\n请选择目标文件``````````````");
                
            }
            else
            {
                byte[] binchar = new byte[] { };            //申请空间
                FileStream Myfile = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read);   //创建对象

                BinaryReader binreader = new BinaryReader(Myfile);      //申请文件缓存空间
                binchar = binreader.ReadBytes((int)Myfile.Length);      //读取文件到内存

  
                SendPack(CommuncationCMD.WriteData, (byte)0xff, binchar, 0);

                binreader.Close();          //  关闭文件
            }
        }

        private void CMB_Port_Click(object sender, EventArgs e)
        {
            ComboBox_Init();
        }


        void ResponseCmd(UInt16 CMD)
        {

            switch (CMD)
            {
                case 0x01:
                    TB_ReceiveAddStr("\r\n设备已连接");
                    SendPack(CommuncationCMD.ACK,0,null,0);
                    break;

                case 0x02:

                    break;

                case 0x03:

                    break;
            }
        }
        
        private void timer1_Tick(object sender, EventArgs e)
        {
            
        }
        //
        //接收状态
        //
        enum ReceiveStatus
        {
            RX_Free = 0,
            RX_CarryOut = 1,
            RX_Busy = 2,
            RX_Error = 3
        };
        //
        //通讯命令
        //
        enum CommuncationCMD
        {
            Connection   = 0x01,
            RunApp       = 0X02,
            EraseFlash   = 0x03,
            WriteData    = 0x04,
            ACK          = 0X30,
            ERR          = 0X31,
        }
        //
        //数据包解析
        //
        struct DataPack_typdef
        {
           
                 
            UInt16  step;
            UInt32 count;
            UInt32 length;
            UInt16 check_sum;
    

            public UInt16 CMD;
            public byte[] Data;
            public UInt16 ErrorNumber;
            public ReceiveStatus Status;



            /******************************************************************
              * @ Name          : void ReceiveError(DataPack_typdef *data_pack)
              * @ Description   : receive error, reset step, save error number 
              * @ Input         : DataPack_typdef *data_pack
              * @ Output        : None
              * @ Return        : None
              * @ Modify the record : ---
            ******************************************************************/
            private void ReceiveError()
            {
                step = 0;
                Status = ReceiveStatus.RX_Error;
                ErrorNumber = step;
            }
           /******************************************************************
             * @ Name          : void PacketParsing(DataPack_typdef *data_pack, uint8_t data)
             * @ Description   : Packet parsing
             * @ Input         : DataPack_typdef *data_pack
             * @ Output        : None
             * @ Return        : None
             * @ Modify the record : ---
           ******************************************************************/
            public void PacketParsing(byte data)
            {

                switch (step)
                {
                    case 0:
                        if (data == 0xeb)                    //header check
                        {
                            step++;
                            Status = ReceiveStatus.RX_Busy;
                        }
                        break;

                    case 1:
                        if (data == 0x91)                    //header check
                        {
                            step++;
                        }
                        else
                        {
                            ReceiveError();
                        }
                        break;

                    case 2:
                        CMD = data;              //save cmd
                        step++;
                        break;

                    case 3:
                        if (data == 0)
                        {
                            step = 0x21;         //no data

                        }
                        else
                        {
                            step = 0x20;         // receive data
                            length = data;
                        }
                        check_sum = 0;
                        count = 0;
                        break;

                    case 0x20:
                        Data[count] = data;
                        check_sum += data;
                        count++;
                        if (count >= length)       //data receive carry out
                        {
                            step = 0x21;
                        }
                        break;

                    case 0x21:
                        if ((check_sum >> 8) == data)           //check sum hight bit
                        {
                            step = 0x22;
                        }
                        else
                        {
                            ReceiveError();
                        }
                        break;


                    case 0x22:
                        if ((check_sum & 0xff) == data)       //check sum low bit
                        {
                            step = 0xff;
                        }
                        else
                        {
                            ReceiveError();
                        }
                        break;


                    case 0xff:
                        if (data == 0x03)                                // tail check                           
                        {
                            step = 0;
                            Status = ReceiveStatus.RX_CarryOut;
                        }
                        else
                        {
                            ReceiveError();
                        }
                        break;
                }
            }
        }

        void SendPack(CommuncationCMD cmd, byte leng, byte[] data, int offset)
        {
            byte[] bBuff = {0xeb, 0x90, (byte)cmd, leng};
            UInt16 CheckSum = 0;
            UInt16 i;
            Console.WriteLine("leng = {0 :D}", leng);
            serialPort1.Write(bBuff, 0, 4);

            if (data != null)
            {
                serialPort1.Write(data, offset, leng);
                for (i = 0; i < leng; i++)
                {
                    CheckSum += data[offset + i];
                }
            }
            bBuff[0] = (byte)((CheckSum >> 8) & 0xff);        //suml
            bBuff[1] = (byte)(CheckSum & 0xff);        //sumh
            bBuff[2] = 0x03;        //尾
            serialPort1.Write(bBuff, 0, 3);   
        }
        
       
    }
}
